package com.wh1200.mybatis.xmlless.model

import com.wh1200.mybatis.xmlless.enums.JoinType
import com.wh1200.mybatis.xmlless.model.component.JoinDeclaration
import com.wh1200.mybatis.xmlless.model.exception.BuildSQLException
import net.sf.jsqlparser.expression.Expression

/**
 * Created by 吴昊 on 2018/12/17.
 */
class ObjectJoinInfo(
    val joinEntityName: String,
    joinTableInfo: XmllessTableInfo,
    val selectProperties: Properties,
    joinTable: TableName,
    type: JoinType,
    joinExpression: Expression,
    targetExpression: Expression,
    /**  关联表查询的列的别名前缀 */
    val associationPrefix: String,
    /**  join的对象或者属性的类型 */
    javaType: TypeInfo,
) : JoinInfo(joinTable, type, joinExpression, targetExpression, javaType, joinTableInfo) {

  override fun selectFields(level: Int, prefix: String?, tablePrefix: String?): List<SelectColumn> {
    if (level > 3) {
      return listOf()
    }
    // 列名称添加前缀防止多表连接的字段名称冲突问题
    val list = wrappedColumns(prefix).map {
      SelectColumn(it.fieldWrapper, TableName(joinTable.name, joinTable.alias.prefixWith(tablePrefix)),
          it.column, it.alias)
    }
    if (hasJoinedProperty()) {
      val mappings = typeInfo.getMappings()
      if (mappings != null) {
        val mappingList = if (selectProperties.isIncludeNotEmpty()) {
          mappings.mappings.filter {
            it.joinInfo != null && it.joinInfo is ObjectJoinInfo && it.property in selectProperties
          }
        } else {
          mappings.mappings.filter {
            it.joinInfo != null && it.joinInfo is ObjectJoinInfo && it.property !in selectProperties.excludes
          }
        }
        return mappingList.map { it.joinInfo!!.selectFields(level + 1, associationPrefix, joinTable.alias) }.flatten() +
            list
      }
    }
    return list
  }

  /**
   * 获取层级join语句
   * @param level 当前join的层数
   */
  fun selectDeepJoins(
      level: Int,
      includedTableAlias: List<String>,
      parentJoinTable: TableName?
  ): List<JoinDeclaration> {
    // 最多支持3级关系
    if (level > 3) {
      return listOf()
    }
    val mappings = typeInfo.getMappings()
    return mappings?.selectJoins(
        level + 1,
        includedTableAlias,
        joinTableName = parentJoinTable
    ) ?: listOf()
  }

  private fun hasJoinedProperty(): Boolean {
    val mappings = typeInfo.getMappings() ?: throw BuildSQLException("无法正确解析join信息：$this")
    return selectProperties.includes.mapNotNull { property ->
      mappings.mappings.firstOrNull { it.property == property }
    }.any { it.joinInfo != null }
  }

  private fun resolveJoinColumns(): List<SelectColumn> {
    val mappings = typeInfo.getMappings() ?: throw BuildSQLException("无法正确解析join信息：$this")
    val joinMappings = selectProperties.includes.mapNotNull { property ->
      mappings.mappings.firstOrNull { it.property == property }
    }.filter { it.joinInfo == null }
    return when {
      joinMappings.isNotEmpty() -> joinMappings.map {
        SelectColumn(it.fieldWrapper, null, it.column, it.property)
      }

      else                      -> mappings.mappings.filter {
        !it.selectIgnore && it.joinInfo == null
      }.map {
        SelectColumn(it.fieldWrapper, null, it.column, it.property)
      }
    }
  }

  private fun wrappedColumns(prefix: String? = null): List<SelectColumn> {
    val fullPrefix = listOf(prefix, associationPrefix).filter { !it.isNullOrBlank() }.joinToString("")
    return resolveJoinColumns().map {
      when {
        it.alias != null -> SelectColumn(
            it.fieldWrapper, it.table, it.column, fullPrefix + it.alias
        )

        else             -> SelectColumn(
            it.fieldWrapper, it.table, it.column, fullPrefix + it.column
        )
      }
    }
  }

}
